package org.jeecg.activiti.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.googlecode.aviator.AviatorEvaluator;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.jeecg.activiti.entity.ActKNodeDesign;
import org.jeecg.activiti.entity.ActScript;
import org.jeecg.activiti.enums.SqlMathEnum;
import org.jeecg.activiti.mapper.ActKNodeDesignMapper;
import org.jeecg.activiti.service.IActKNodeDesignService;
import org.jeecg.modules.online.cgform.mapper.OnlCgformFieldMapper;
import org.jeecg.modules.online.config.exception.ActScriptException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Service
@Slf4j
public class ActKNodeDesignServiceImpl extends ServiceImpl<ActKNodeDesignMapper, ActKNodeDesign> implements IActKNodeDesignService {

    @Autowired
    private OnlCgformFieldMapper onlCgformFieldMapper;
    private static final String sqlBlankStr = " ";

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void postProcessFormdataByScript(String modelId, String taskId, Map<String, Object> variables ) throws ActScriptException {
    	ActKNodeDesign actKNodeDesign = null;
    	try{
    		actKNodeDesign = this.getOne(new QueryWrapper<ActKNodeDesign>()
                    .eq("model_id", modelId)
                    .eq("node_id", taskId));
    	}catch (Exception e) {
			// TODO: handle exception
		}
        
        if(actKNodeDesign == null){
        	log.info("modelId：{}，taskId：{} 没有定义节点脚本",modelId,taskId);
            return;
        }
        String nodeScript = actKNodeDesign.getNodeScript();
        if(StringUtils.isBlank(nodeScript)){
            log.info("modelId：{}，taskId：{} 没有定义节点脚本",modelId,taskId);
            return;
        }

        List<String> sqlList = parsScrip(nodeScript, variables);
        for(String sql:sqlList){
            onlCgformFieldMapper.editFormData(sql);
        }
    }

    public static void validateScripts(String nodeScript) throws ActScriptException {

        List<ActScript> actScripts = getActScripts(nodeScript);
        for(ActScript script:actScripts ) {
            String option = script.getOption();
            String tableName = script.getTableName();
            ArrayList<String> columeNames = script.getColumeNames();
            ArrayList<ActScript.Condition> conditions = script.getConditions();
            Integer columSize = columeNames.size();
            ArrayList<ActScript.Value> values = script.getValues();
            validateParams(option, tableName, columeNames, conditions, columSize, values);
        }
    }


    private  List<String> parsScrip(String nodeScript,Map<String,Object> variables) throws ActScriptException {
        List<ActScript> actScripts = getActScripts(nodeScript);
        List<String> sqlList = new ArrayList<>(actScripts.size());

        for(ActScript script:actScripts ){

            String option = script.getOption();
            String tableName = script.getTableName();
            ArrayList<String> columeNames = script.getColumeNames();
            ArrayList<ActScript.Condition> conditions = script.getConditions();
            Integer columSize = columeNames.size();
            ArrayList<ActScript.Value> values = script.getValues();

            validateParams(option, tableName, columeNames, conditions, columSize, values);


            StringBuilder sql = new StringBuilder("");
            if(StringUtils.equalsIgnoreCase(option,"update")){
                buildUpdateSql(option, tableName, columeNames, conditions, columSize, values, sql,variables);
            }else if(StringUtils.equalsIgnoreCase(option,"insert")){
                //todo 创建 插入操作 脚本
                buildInsertSql(variables, option, tableName, columeNames, columSize, values, sql);
            }
            log.info("scriptSql: {}", sql);
            sqlList.add(sql.toString());
        }
        return sqlList;

    }

    private void buildInsertSql(Map<String, Object> variables, String option, String tableName, ArrayList<String> columeNames, Integer columSize, ArrayList<ActScript.Value> values, StringBuilder sql) throws ActScriptException {
        sql.append(option).append(sqlBlankStr);//insert
        sql.append("into").append(sqlBlankStr); // into
        sql.append(tableName).append(sqlBlankStr);  //table
        sql.append("(").append(sqlBlankStr);
        for(int i = 0;i< columSize;i++){
            sql.append(columeNames.get(i));
            if (i+1<columSize) {
                sql.append(",");
            }
        }
        sql.append(")").append(sqlBlankStr);
        sql.append("values").append(sqlBlankStr);
        sql.append("(").append(sqlBlankStr);

        for(int i = 0;i< columSize;i++){
            //todo 此处是变量
            ActScript.Value value = values.get(i);
            Boolean isExp = value.getIsExp();
            String valueColumeName = value.getValueColumeName();
            if(isExp){
                //sql.append(AviatorEvaluator.execute("1+2+3")).append(sqlBlankStr);
            }else{
                Object insertColumeVal = variables.get(valueColumeName);
                if(insertColumeVal == null){
                    throw new ActScriptException("脚本错误，操作类型：insert ，设置的valueColumeName在主表中不存在,valueColumeName: "+ valueColumeName);
                }
                if(insertColumeVal instanceof String){
                    sql.append("'").append(insertColumeVal).append("'");
                }else{
                    sql.append(insertColumeVal);
                }
            }
            if(i+1<columSize){
                sql.append(",").append(sqlBlankStr);
            }
        }
        sql.append(");").append(sqlBlankStr);
    }

    private static void buildUpdateSql(String option, String tableName, ArrayList<String> columeNames, ArrayList<ActScript.Condition> conditions, Integer columSize, ArrayList<ActScript.Value> values, StringBuilder sql,Map<String,Object> variables) throws ActScriptException {
        sql.append(option).append(sqlBlankStr);
        sql.append(tableName).append(sqlBlankStr);
        sql.append("set").append(sqlBlankStr);

        for(int i = 0;i< columSize;i++){
            sql.append(columeNames.get(i)).append("=");
            //todo 此处是变量
            ActScript.Value value = values.get(i);
            Boolean isExp = value.getIsExp();
            String valueColumeName = value.getValueColumeName();
            if(isExp){
                sql.append(AviatorEvaluator.execute("1+2+3")).append(sqlBlankStr);
            }else{
                Object setColumeVal = variables.get(valueColumeName);
                if(setColumeVal == null){
                    throw new ActScriptException("脚本错误，操作类型：update ，设置的valueColumeName在主表中不存在,valueColumeName: "+ valueColumeName);
                }
                if(setColumeVal instanceof String){
                    sql.append("'").append(setColumeVal).append("'").append(sqlBlankStr);
                }else{
                    sql.append(setColumeVal).append(sqlBlankStr);
                }
            }
            if(i+1<columSize){
                sql.append(",").append(sqlBlankStr);
            }
        }

        sql.append("where").append(sqlBlankStr);
        StringBuilder whereCond = new StringBuilder();
        for(ActScript.Condition condition : conditions){
            if(StringUtils.isBlank(whereCond)){
                whereCond.append(condition.getWhereColumeName());
            }else {
                whereCond.append("and").append(sqlBlankStr).append(condition.getWhereColumeName());
            }
            //todo 此处是变量
            String wherevalueColumn = condition.getWherevalueColumn();
            Object whereColumeVal = variables.get(wherevalueColumn);
            if(whereColumeVal == null){
                throw new ActScriptException("脚本错误，设置的valueColumeName在主表中不存在,wherevalueColumn: "+ wherevalueColumn);
            }
            whereCond.append(SqlMathEnum.getSymbol(condition.getMatch().toUpperCase()));
            if(whereColumeVal instanceof String){
                whereCond.append("'").append(whereColumeVal).append("'").append(sqlBlankStr);
            }else{
                whereCond.append(whereColumeVal).append(sqlBlankStr);
            }

        }
        sql.append(whereCond);
    }

    private static void validateParams(String option, String tableName, ArrayList<String> columeNames, ArrayList<ActScript.Condition> conditions, Integer columSize, ArrayList<ActScript.Value> values) throws ActScriptException {
        if(StringUtils.isBlank(option)){
            throw new ActScriptException("脚本错误，option 不能为空窜或者 null");
        }
        if(StringUtils.isBlank(tableName)){
            throw new ActScriptException("脚本错误，tableName 不能为空窜或者 null");
        }
        if(CollectionUtils.isEmpty(columeNames)){
            throw new ActScriptException("脚本错误，columeNames 不能为空窜或者 null");
        }

        ArrayList<String> illegalColumNames = new ArrayList<>();
        illegalColumNames.add("");
        illegalColumNames.add(" ");
        illegalColumNames.add(null);
        if(CollectionUtils.containsAny(columeNames,illegalColumNames)){
            throw new ActScriptException("脚本错误，columeNames列表不能包含空窜或者null");
        }

        if(columSize.compareTo(values.size()) != 0){
            throw new ActScriptException("脚本错误，columeNames列表长度必须和 values 列表长度相等");
        }
        if(CollectionUtils.containsAny(columeNames,illegalColumNames)){
            throw new ActScriptException("脚本错误，columeNames列表不能包含空窜或者null");
        }

        if(StringUtils.equals("update",option) && CollectionUtils.isEmpty(conditions)){
            throw new ActScriptException("脚本错误，操作类型为update时，conditions列表不能包含空窜或者null");
        }
    }

    //@Nullable
    private static List<ActScript> getActScripts(String nodeScript) throws ActScriptException {
        List<ActScript> actScripts;
        try {
            actScripts = JSON.parseObject(nodeScript, new TypeReference<List<ActScript>>() {});
            log.info("actScripts:    {}",actScripts );
        } catch (Exception e) {
            throw new ActScriptException("脚本格式错误，正确格式为："+
                    "[{option:\"update\",scope:\"task\",tableName:\"tableName1\",columeNames:[\"name1\",\"name2\"],values:[{valueColumeName:\"zhangsan\",isExp:false},{valueColumeName:\"lisi+wangwu\",isExp:true}]," +
                    "conditions:[{whereColumeName:\"age\",match:\"eq\",wherevalueColumn:\"age\"},{whereColumeName:\"age1\",match:\"eq\",wherevalueColumn:\"age1\"}]}]"
            );
        }

        return actScripts;
    }

   /* public static void main(String[] args) throws ActScriptException {

        *//*String nodeScript = "[{option:\"update\",scope:\"task\",tableName:\"test_act_script\",columeNames:[\"name\",\"age\"],values:[{valueColumeName:\"name\",isExp:false},{valueColumeName:\"age\",isExp:false}]," +
                "conditions:[{whereColumeName:\"id\",match:\"eq\",wherevalueColumn:\"id\"},{whereColumeName:\"score\",match:\"eq\",wherevalueColumn:\"score\"}]}]";*//*

       // String nodeScript = "[{option:\"update\",scope:\"task\",tableName:\"test_act_script\",columeNames:[\"name\",\"age\"],values:[{valueColumeName:\"id\",isExp:false},{valueColumeName:\"id\",isExp:false}],conditions:[{whereColumeName:\"id\",match:\"eq\",wherevalueColumn:\"id\"},{whereColumeName:\"score\",match:\"eq\",wherevalueColumn:\"id\"}]}]";
       String nodeScript = "[{option:'update',scope:'task',tableName:'test_act_script',columeNames:['name','age'],values:[{valueColumeName:'name',isExp:false},{valueColumeName:'age',isExp:false}],conditions:[{whereColumeName:'id',match:'eq',wherevalueColumn:'id'},[{option:\"inset\",scope:\"task\",tableName:\"test_act_script\",columeNames:[\"id\",\"name\",\"age\"],values:[{valueColumeName:\"id\",isExp:false,isPk:ture,pkSrc:\"sys\"},{valueColumeName:\"name\",isExp:false},{valueColumeName:\"age\",isExp:false}]}]";
        List<ActScript>  actScripts =  JSON.parseObject(nodeScript, new TypeReference<List<ActScript>>() {});
        //JSONArray jsonArray = JSON.parseArray(nodeScript);
        System.out.println(actScripts.get(0).getConditions().get(0).getMatch());
        Map<String,Object> vars = new HashMap<>();
        vars.put("id",1);
        vars.put("name","zhangsan");
        vars.put("age",10);
        vars.put("score",81.5);
        new ActKNodeDesignServiceImpl().parsScrip(nodeScript,vars);

    }*/


}



